﻿using System.Collections.Generic;

public enum ActorPropertyType
{
    maxLife,
    life,
    lifeRecovery,
    maxMagic,
    magic,
    magicRecovery,
    maxPhysicsAttack,
    physicsAttack,
    maxPhysicsDefense,
    physicsDefense,
    maxMagicAttack,
    magicAttack,
    maxMagicDefense,
    magicDefense,
    maxMoveSpeed,
    moveSpeed,
    maxAttackSpeed,
    attackSpeed,
    maxAttackDistance,
    attackDistance,
    physicsCritRate,
    magicCritRate,
    critDamageRate,
    physicsDrainRate,
    magicDrainRate,
    coolDownReduceRate,
    max,
}

public enum PropertyValueType
{
    number,
    percent,
}

public class PropertyItem
{
    public ActorPropertyType propertyType;
    public float propertyValue;
    public PropertyValueType propertyValueType;
}

public class PropertyController
{
    private int mLevel;

    private int mBaseLife;
    private int mMaxLife;
    private int mLife;
    private int mLifeRecovery;

    private int mBaseMagic;
    private int mMaxMagic;
    private int mMagic;
    private int mMagicRecovery;

    private int mBasePhysicsAttack;
    private int mMaxPhysicsAttack;
    private int mPhysicsAttack;

    private int mBasePhysicsDefense;
    private int mMaxPhysicsDefense;
    private int mPhysicsDefense;

    private int mBaseMagicAttack;
    private int mMaxMagicAttack;
    private int mMagicAttack;

    private int mBaseMagicDefense;
    private int mMaxMagicDefense;
    private int mMagicDefense;

    private float mBaseMoveSpeed;
    private float mMaxMoveSpeed;
    private float mMoveSpeed;

    private float mBaseAttackSpeed;
    private float mMaxAttackSpeed;
    private float mAttackSpeed;

    private float mBaseAttackDistance;
    private float mMaxAttackDistance;
    private float mAttackDistance;

    private float mBasePhysicsCritRate;
    private float mPhysicsCritRate;

    private float mBaseMagicCritRate;
    private float mMagicCritRate;

    private float mBaseCritDamageRate;
    private float mCritDamageRate;

    private float mBasePhysicsDrainRate;
    private float mPhysicsDrainRate;

    private float mBaseMagicDrainRate;
    private float mMagicDrainRate;

    private float mBaseCoolDownReduceRate;
    private float mCoolDownReduceRate;

    public int Level
    {
        get
        {
            return mLevel;
        }
    }

    public int BaseLife
    {
        get
        {
            return mBaseLife;
        }
    }

    public int MaxLife
    {
        get
        {
            return mMaxLife;
        }
    }

    public int Life
    {
        get
        {
            return mLife;
        }
    }

    public int LifeRecovery
    {
        get
        {
            return mLifeRecovery;
        }
    }

    public int BaseMagic
    {
        get
        {
            return mBaseMagic;
        }
    }

    public int MaxMagic
    {
        get
        {
            return mMaxMagic;
        }
    }

    public int Magic
    {
        get
        {
            return mMagic;
        }
    }

    public int MagicRecovery
    {
        get
        {
            return mMagicRecovery;
        }
    }

    public int BasePhysicsAttack
    {
        get
        {
            return mBasePhysicsAttack;
        }
    }

    public int MaxPhysicsAttack
    {
        get
        {
            return mMaxPhysicsAttack;
        }
    }

    public int PhysicsAttack
    {
        get
        {
            return mPhysicsAttack;
        }
    }

    public int BasePhysicsDefense
    {
        get
        {
            return mBasePhysicsDefense;
        }
    }

    public int MaxPhysicsDefense
    {
        get
        {
            return mMaxPhysicsDefense;
        }
    }

    public int PhysicsDefense
    {
        get
        {
            return mPhysicsDefense;
        }
    }

    public int BaseMagicAttack
    {
        get
        {
            return mBaseMagicAttack;
        }
    }

    public int MaxMagicAttack
    {
        get
        {
            return mMaxMagicAttack;
        }
    }

    public int MagicAttack
    {
        get
        {
            return mMagicAttack;
        }
    }

    public int BaseMagicDefense
    {
        get
        {
            return mBaseMagicDefense;
        }
    }

    public int MaxMagicDefense
    {
        get
        {
            return mMaxMagicDefense;
        }
    }

    public int MagicDefense
    {
        get
        {
            return mMagicDefense;
        }
    }

    public float BaseMoveSpeed
    {
        get
        {
            return mBaseMoveSpeed;
        }
    }

    public float MaxMoveSpeed
    {
        get
        {
            return mMaxMoveSpeed;
        }
    }

    public float MoveSpeed
    {
        get
        {
            return mMoveSpeed;
        }
    }

    public float BaseAttackSpeed
    {
        get
        {
            return mBaseAttackSpeed;
        }
    }

    public float MaxAttackSpeed
    {
        get
        {
            return mMaxAttackSpeed;
        }
    }

    public float AttackSpeed
    {
        get
        {
            return mAttackSpeed;
        }
    }

    public float BaseAttackDistance
    {
        get
        {
            return mBaseAttackDistance;
        }
    }

    public float MaxAttackDistance
    {
        get
        {
            return mMaxAttackDistance;
        }
    }

    public float AttackDistance
    {
        get
        {
            return mAttackDistance;
        }
    }

    private float BasePhysicsCritRate
    {
        get
        {
            return mBasePhysicsCritRate;
        }
    }

    public float PhysicsCritRate
    {
        get
        {
            return mPhysicsCritRate;
        }
    }

    public float BaseMagicCritRate
    {
        get
        {
            return mBaseMagicCritRate;
        }
    }

    public float MagicCritRate
    {
        get
        {
            return mMagicCritRate;
        }
    }

    public float BaseCritDamageRate
    {
        get
        {
            return mBaseCritDamageRate;
        }
    }

    public float CritDamageRate
    {
        get
        {
            return mCritDamageRate;
        }
    }

    public float BasePhysicsDrainRate
    {
        get
        {
            return mBasePhysicsDrainRate;
        }
    }

    public float PhysicsDrainRate
    {
        get
        {
            return mPhysicsDrainRate;
        }
    }

    public float BaseMagicDrainRate
    {
        get
        {
            return mBaseMagicDrainRate;
        }
    }

    public float MagicDrainRate
    {
        get
        {
            return mMagicDrainRate;
        }
    }

    public float BaseCoolDownReduceRate
    {
        get
        {
            return mBaseCoolDownReduceRate;
        }
    }

    public float CoolDownReduceRate
    {
        get
        {
            return mCoolDownReduceRate;
        }
    }

    public System.Action<ActorPropertyType, float> OnPropertyValueChangedEvent;

    private ActorValueTable.ActorValueEntry mActorValueEntry;

    public void OnStart()
    {

    }

    public void SetActorValueEntry(ActorValueTable.ActorValueEntry actorValueEntry)
    {
        this.mActorValueEntry = actorValueEntry;
    }

    public void SetLevel(int level)
    {
        this.mLevel = level;

        mBaseLife = mActorValueEntry.baseLife + mActorValueEntry.lifeGrowth * level;
        mMaxLife = mBaseLife;
        mLife = mBaseLife;
        mLifeRecovery = mActorValueEntry.lifeRecovery;

        mBaseMagic = mActorValueEntry.baseMagic + mActorValueEntry.magicGrowth * level;
        mMaxMagic = mBaseMagic;
        mMagic = mBaseMagic;
        mMagicRecovery = mActorValueEntry.magicRecovery;

        mBasePhysicsAttack = mActorValueEntry.basePhysicsAttack + mActorValueEntry.lifeGrowth * level;
        mMaxPhysicsAttack = mBasePhysicsAttack;
        mPhysicsAttack = mBasePhysicsAttack;

        mBasePhysicsDefense = mActorValueEntry.basePhysicsDefense + mActorValueEntry.physicsDefenseGrowth * level;
        mMaxPhysicsDefense = mBasePhysicsDefense;
        mPhysicsDefense = mBasePhysicsDefense;

        mBaseMagicAttack = mActorValueEntry.baseMagicAttack + mActorValueEntry.magicAttackGrowth * level;
        mMaxMagicAttack = mBaseMagicAttack;
        mMagicAttack = mBaseMagicAttack;

        mBaseMagicDefense = mActorValueEntry.baseMagicDefense + mActorValueEntry.magicDefenseGrowth * level;
        mMaxMagicDefense = mBaseMagicDefense;
        mMagicDefense = mBaseMagicDefense;

        mBaseMoveSpeed = mActorValueEntry.baseMoveSpeed;
        mMaxMoveSpeed = mBaseMoveSpeed;
        mMoveSpeed = mBaseMoveSpeed;

        mBaseAttackSpeed = mActorValueEntry.baseAttackSpeed + mActorValueEntry.attackSpeedGrowth * level;
        mMaxAttackSpeed = mBaseAttackSpeed;
        mAttackSpeed = mBaseAttackSpeed;

        mBaseAttackDistance = mActorValueEntry.baseAttackDistance + mActorValueEntry.attackDistanceGrowth * level;
        mMaxAttackDistance = mBaseAttackDistance;
        mAttackDistance = mBaseAttackDistance;

        mBasePhysicsCritRate = mActorValueEntry.basePhysicsCritRate + mActorValueEntry.physicsCritRateGrowth * level;
        mPhysicsCritRate = mBasePhysicsCritRate;

        mBaseMagicCritRate = mActorValueEntry.baseMagicCritRate + mActorValueEntry.magicCritRateGrowth * level;
        mMagicCritRate = mBaseMagicCritRate;

        mBaseCritDamageRate = mActorValueEntry.baseCritDamageRate + mActorValueEntry.critDamageRateGrowth * level;
        mCritDamageRate = mBaseCritDamageRate;

        mBasePhysicsDrainRate = mActorValueEntry.basePhysicsDrainRate + mActorValueEntry.physicsDrainRateGrowth * level;
        mPhysicsDrainRate = mBasePhysicsDrainRate;

        mBaseMagicDrainRate = mActorValueEntry.baseMagicDrainRate + mActorValueEntry.magicDrainRateGrowth * level;
        mMagicDrainRate = mBaseMagicDrainRate;

        mBaseCoolDownReduceRate = mActorValueEntry.baseCoolDownReduceRate + mActorValueEntry.coolDownReduceRateGrowth * level;
        mCoolDownReduceRate = mBaseCoolDownReduceRate;
    }

    public void SetPropertyValue(ActorPropertyType propertyType, float propertyValue)
    {
        switch (propertyType)
        {
            case ActorPropertyType.maxLife:
                mMaxLife = (int)propertyValue;
                break;
            case ActorPropertyType.life:
                mLife = (int)propertyValue;
                break;
            case ActorPropertyType.lifeRecovery:
                mLifeRecovery = (int)propertyValue;
                break;
            case ActorPropertyType.maxMagic:
                mMaxMagic = (int)propertyValue;
                break;
            case ActorPropertyType.magic:
                mMagic = (int)propertyValue;
                break;
            case ActorPropertyType.magicRecovery:
                mMagicRecovery = (int)propertyValue;
                break;
            case ActorPropertyType.maxPhysicsAttack:
                mMaxPhysicsAttack = (int)propertyValue;
                break;
            case ActorPropertyType.physicsAttack:
                mPhysicsAttack = (int)propertyValue;
                break;
            case ActorPropertyType.maxPhysicsDefense:
                mMaxPhysicsDefense = (int)propertyValue;
                break;
            case ActorPropertyType.physicsDefense:
                mPhysicsDefense = (int)propertyValue;
                break;
            case ActorPropertyType.maxMagicAttack:
                mMaxMagicAttack = (int)propertyValue;
                break;
            case ActorPropertyType.magicAttack:
                mMaxMagicAttack = (int)propertyValue;
                break;
            case ActorPropertyType.maxMagicDefense:
                mMaxMagicDefense = (int)propertyValue;
                break;
            case ActorPropertyType.magicDefense:
                mMagicDefense = (int)propertyValue;
                break;
            case ActorPropertyType.maxMoveSpeed:
                mMaxMoveSpeed = propertyValue;
                break;
            case ActorPropertyType.moveSpeed:
                mMoveSpeed = propertyValue;
                break;
            case ActorPropertyType.maxAttackSpeed:
                mMaxAttackSpeed = propertyValue;
                break;
            case ActorPropertyType.attackSpeed:
                mAttackSpeed = propertyValue;
                break;
            case ActorPropertyType.maxAttackDistance:
                mMaxAttackDistance = propertyValue;
                break;
            case ActorPropertyType.attackDistance:
                mAttackDistance = propertyValue;
                break;
            case ActorPropertyType.physicsCritRate:
                mPhysicsCritRate = propertyValue;
                break;
            case ActorPropertyType.magicCritRate:
                mMagicCritRate = propertyValue;
                break;
            case ActorPropertyType.critDamageRate:
                mCritDamageRate = propertyValue;
                break;
            case ActorPropertyType.physicsDrainRate:
                mPhysicsDrainRate = propertyValue;
                break;
            case ActorPropertyType.magicDrainRate:
                mMagicDrainRate = propertyValue;
                break;
            case ActorPropertyType.coolDownReduceRate:
                mCoolDownReduceRate = propertyValue;
                break;
        }
    }

    public void AddPropertyValue(ActorPropertyType actorPropertyType, float propertyValue)
    {
        switch (actorPropertyType)
        {
            case ActorPropertyType.maxLife:
                mMaxLife += (int)propertyValue;
                mLife += (int)propertyValue;
                break;
            case ActorPropertyType.life:
                mLife += (int)propertyValue;
                if (mLife > mMaxLife)
                {
                    mLife = mMaxLife;
                }
                break;
            case ActorPropertyType.lifeRecovery:
                mLifeRecovery += (int)propertyValue;
                break;
            case ActorPropertyType.maxMagic:
                mMaxMagic += (int)propertyValue;
                mMagic += (int)propertyValue;
                break;
            case ActorPropertyType.magic:
                mMagic += (int)propertyValue;
                if (mMagic > mMaxMagic)
                {
                    mMagic = mMaxMagic;
                }
                break;
            case ActorPropertyType.magicRecovery:
                mMagicRecovery += (int)propertyValue;
                break;
            case ActorPropertyType.maxPhysicsAttack:
                mMaxPhysicsAttack += (int)propertyValue;
                mPhysicsAttack += (int)propertyValue;
                break;
            case ActorPropertyType.physicsAttack:
                mPhysicsAttack += (int)propertyValue;
                if (mPhysicsAttack > mMaxPhysicsAttack)
                {
                    mPhysicsAttack = mMaxPhysicsAttack;
                }
                break;
            case ActorPropertyType.maxPhysicsDefense:
                mMaxPhysicsDefense += (int)propertyValue;
                mPhysicsDefense += (int)propertyValue;
                break;
            case ActorPropertyType.physicsDefense:
                mPhysicsDefense += (int)propertyValue;
                if (mPhysicsDefense > mMaxPhysicsDefense)
                {
                    mPhysicsDefense = mMaxPhysicsDefense;
                }
                break;
            case ActorPropertyType.maxMagicAttack:
                mMaxMagicAttack += (int)propertyValue;
                mMagicAttack += (int)propertyValue;
                break;
            case ActorPropertyType.magicAttack:
                mMagicAttack += (int)propertyValue;
                if (mMagicAttack > mMaxMagicAttack)
                {
                    mMagicAttack = mMaxMagicAttack;
                }
                break;
            case ActorPropertyType.maxMagicDefense:
                mMaxMagicDefense += (int)propertyValue;
                mMagicDefense += (int)propertyValue;
                break;
            case ActorPropertyType.magicDefense:
                mMagicDefense += (int)propertyValue;
                if (mMagicDefense > mMaxMagicDefense)
                {
                    mMagicDefense = mMaxMagicDefense;
                }
                break;
            case ActorPropertyType.maxMoveSpeed:
                mMaxMoveSpeed += propertyValue;
                mMoveSpeed += propertyValue;
                break;
            case ActorPropertyType.moveSpeed:
                mMoveSpeed += propertyValue;
                if (mMoveSpeed > mMaxMoveSpeed)
                {
                    mMoveSpeed = mMaxMoveSpeed;
                }
                break;
            case ActorPropertyType.maxAttackSpeed:
                mMaxAttackSpeed += propertyValue;
                mAttackSpeed += propertyValue;
                break;
            case ActorPropertyType.attackSpeed:
                mAttackSpeed += propertyValue;
                if (mAttackSpeed > mMaxAttackSpeed)
                {
                    mAttackSpeed = mMaxAttackSpeed;
                }
                break;
            case ActorPropertyType.maxAttackDistance:
                mMaxAttackDistance += propertyValue;
                mAttackDistance += propertyValue;
                break;
            case ActorPropertyType.attackDistance:
                mAttackDistance += propertyValue;
                if (mAttackDistance > mMaxAttackDistance)
                {
                    mAttackDistance = mMaxAttackDistance;
                }
                break;
            case ActorPropertyType.physicsCritRate:
                mPhysicsCritRate += propertyValue;
                break;
            case ActorPropertyType.magicCritRate:
                mMagicCritRate += propertyValue;
                break;
            case ActorPropertyType.critDamageRate:
                mCritDamageRate += propertyValue;
                break;
            case ActorPropertyType.physicsDrainRate:
                mPhysicsDrainRate += propertyValue;
                break;
            case ActorPropertyType.magicDrainRate:
                mMagicDrainRate += propertyValue;
                break;
            case ActorPropertyType.coolDownReduceRate:
                mCoolDownReduceRate += propertyValue;
                break;
        }

        if (OnPropertyValueChangedEvent != null)
        {
            if (propertyValue > float.Epsilon || propertyValue < -float.Epsilon)
            {
                OnPropertyValueChangedEvent(actorPropertyType, propertyValue);
            }
        }
    }

    public float GetPropertyValue(ActorPropertyType propertyType)
    {
        float propertyValue = 0.0f;

        switch (propertyType)
        {
            case ActorPropertyType.maxLife:
                propertyValue = mMaxLife;
                break;
            case ActorPropertyType.life:
                propertyValue = mLife;
                break;
            case ActorPropertyType.lifeRecovery:
                propertyValue = mLifeRecovery;
                break;
            case ActorPropertyType.maxMagic:
                propertyValue = mMaxMagic;
                break;
            case ActorPropertyType.magic:
                propertyValue = mMagic;
                break;
            case ActorPropertyType.magicRecovery:
                propertyValue = mMagicRecovery;
                break;
            case ActorPropertyType.maxPhysicsAttack:
                propertyValue = mMaxPhysicsAttack;
                break;
            case ActorPropertyType.physicsAttack:
                propertyValue = mPhysicsAttack;
                break;
            case ActorPropertyType.maxPhysicsDefense:
                propertyValue = mMaxPhysicsDefense;
                break;
            case ActorPropertyType.physicsDefense:
                propertyValue = mPhysicsDefense;
                break;
            case ActorPropertyType.maxMagicAttack:
                propertyValue = mMaxMagicAttack;
                break;
            case ActorPropertyType.magicAttack:
                propertyValue = mMagicAttack;
                break;
            case ActorPropertyType.maxMagicDefense:
                propertyValue = mMaxMagicDefense;
                break;
            case ActorPropertyType.magicDefense:
                propertyValue = mMagicDefense;
                break;
            case ActorPropertyType.maxMoveSpeed:
                propertyValue = mMaxMoveSpeed;
                break;
            case ActorPropertyType.moveSpeed:
                propertyValue = mMoveSpeed;
                break;
            case ActorPropertyType.maxAttackSpeed:
                propertyValue = mMaxAttackSpeed;
                break;
            case ActorPropertyType.attackSpeed:
                propertyValue = mAttackSpeed;
                break;
            case ActorPropertyType.maxAttackDistance:
                propertyValue = mMaxAttackDistance;
                break;
            case ActorPropertyType.attackDistance:
                propertyValue = mAttackDistance;
                break;
            case ActorPropertyType.physicsCritRate:
                propertyValue = mPhysicsCritRate;
                break;
            case ActorPropertyType.magicCritRate:
                propertyValue = mMagicCritRate;
                break;
            case ActorPropertyType.critDamageRate:
                propertyValue = mCritDamageRate;
                break;
            case ActorPropertyType.physicsDrainRate:
                propertyValue = mPhysicsDrainRate;
                break;
            case ActorPropertyType.magicDrainRate:
                propertyValue = mMagicDrainRate;
                break;
            case ActorPropertyType.coolDownReduceRate:
                propertyValue = mCoolDownReduceRate;
                break;
        }

        return propertyValue;
    }

    public float CalculatePropertyPercentValue(ActorPropertyType propertyType, float propertyPercent)
    {
        float propertyNumberValue = 0;

        switch (propertyType)
        {
            case ActorPropertyType.maxLife:
                propertyNumberValue = (mMaxLife * propertyPercent);
                break;
            case ActorPropertyType.maxMagic:
                propertyNumberValue = (mMaxMagic * propertyPercent);
                break;
            case ActorPropertyType.maxPhysicsAttack:
                propertyNumberValue = (mMaxPhysicsAttack * propertyPercent);
                break;
            case ActorPropertyType.maxPhysicsDefense:
                propertyNumberValue = (mMaxPhysicsDefense * propertyPercent);
                break;
            case ActorPropertyType.maxMagicAttack:
                propertyNumberValue = (mMaxMagicAttack * propertyPercent);
                break;
            case ActorPropertyType.maxMagicDefense:
                propertyNumberValue = (mMaxMagicDefense * propertyPercent);
                break;
            case ActorPropertyType.maxMoveSpeed:
                propertyNumberValue = (mMaxMoveSpeed * propertyPercent);
                break;
            case ActorPropertyType.maxAttackSpeed:
                propertyNumberValue = (mMaxAttackSpeed * propertyPercent);
                break;
            case ActorPropertyType.maxAttackDistance:
                propertyNumberValue = (mMaxAttackDistance * propertyPercent);
                break;
        }

        return propertyNumberValue;
    }
}